package com.lkdont.android.media.examples.ui.video.camera

import android.Manifest
import android.graphics.Rect
import android.graphics.SurfaceTexture
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.TextureView
import android.view.View
import android.view.ViewGroup
import com.lkdont.android.base.ui.BaseFrag
import com.lkdont.android.media.camera.OldCameraManager
import com.lkdont.android.media.examples.R
import kotlinx.android.synthetic.main.frag_record_camera_video_1.*
import java.io.FileOutputStream
import java.io.OutputStream
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit


/**
 * 录制摄像头视频例子
 *
 * @author lkdont
 */
class RecordCameraVideoFrag1 : BaseFrag() {

    companion object {

        private const val REQ_ID_PERMISSIONS = 101

        private val PERMISSIONS = arrayOf(
            Manifest.permission.CAMERA,
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
        )
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.frag_record_camera_video_1, container, false)
    }

    /*** 初始化视频UI */
    private fun initVideoView() {
        videoView.surfaceTextureListener = surfaceTextureListener
//        videoView.eventListener = object : CameraPreviewView.EventListener {
//
//            override fun onPreviewStart() {
//                Logger.d(this, "onPreviewStart: 开始预览")
//            }
//
//            override fun onPreviewStop() {
//                Logger.d(this, "onPreviewStop: 停止预览")
//            }
//
//            override fun onError(e: CameraException) {
//                e.printStackTrace()
//                showMessage(e.message)
//            }
//        }
//        videoView.recorder = videoRecorder
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // 初始化视频UI
        initVideoView()
        // 设置点击事件
        recordBtn.setOnClickListener {
            toggleRecording()
        }
        switchCameraBtn.setOnClickListener {
            switchCamera()
        }
    }

    private var recording = false
    private var recordingTask: EncodeTask? = null

    private fun toggleRecording() {
        recording = !recording
        if (recording) {
            if (recordingTask != null) {
                recordingTask!!.stopRunning()
            }
            recordingTask = EncodeTask()
            recordingTask?.start()
        } else {
            recordingTask?.stopRunning()
            recordingTask = null
        }
        updateRecordingUi()
    }

    private fun updateRecordingUi() {
        if (recording) {
            recordBtn.text = "停止录制"
        } else {
            recordBtn.text = "开始录制"
        }
    }

    private var selectedCameraId = OldCameraManager.CameraType.BACK_CAMERA.id

    private fun switchCamera() {
        selectedCameraId = if (selectedCameraId == OldCameraManager.CameraType.BACK_CAMERA.id) {
            OldCameraManager.CameraType.FRONT_CAMERA.id
        } else {
            OldCameraManager.CameraType.BACK_CAMERA.id
        }
        updateSwitchCameraBtn()
        // 切换摄像头
        stopPreview()
        startPreview(selectedCameraId)
    }

    private fun updateSwitchCameraBtn() {
        if (selectedCameraId == OldCameraManager.CameraType.BACK_CAMERA.id) {
            switchCameraTv.setText(R.string.back_camera)
        } else {
            switchCameraTv.setText(R.string.front_camera)
        }
    }

    override fun onResume() {
        super.onResume()
        // 开始预览
        startPreview(selectedCameraId)
        // 更新UI
        updateRecordingUi()
        updateSwitchCameraBtn()
    }

    override fun onPause() {
        super.onPause()
        // 停止预览
        stopPreview()
    }

    //******************************** 权限 ********************************//

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == REQ_ID_PERMISSIONS) {
            if (hasPermissions(PERMISSIONS)) {
                startPreview(selectedCameraId)
            } else {
                showMessage(R.string.no_permission)
            }
        }
    }

    //******************************** 摄像头 ********************************//

    private var previewSurfaceTexture: SurfaceTexture? = null

    private val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
        override fun onSurfaceTextureAvailable(
            surface: SurfaceTexture?,
            width: Int,
            height: Int
        ) {
            previewSurfaceTexture = surface
            if (surface != null && OldCameraManager.instance.isOpened()) {
                OldCameraManager.instance.startPreview(surface, cameraPreviewCallback)
            }
        }

        override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean {
            previewSurfaceTexture = null
            stopPreview()
            return true
        }

        override fun onSurfaceTextureSizeChanged(
            surface: SurfaceTexture?,
            width: Int,
            height: Int
        ) {
        }

        override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) {
        }
    }

    private var videoWidth: Int = 0
    private var videoHeight: Int = 0

    private fun startPreview(cameraId: Int) {
        if (!hasPermissions(PERMISSIONS)) {
            // 没有权限
            requestPermissions(
                PERMISSIONS,
                REQ_ID_PERMISSIONS
            )
            return
        }
        // 检查摄像头是否已经打开
        if (OldCameraManager.instance.isOpened()) {
            showMessage("摄像头已经开启")
            return
        }
        // 打开摄像头
        if (!OldCameraManager.instance.openCamera(cameraId)) {
            showMessage("打开摄像头失败")
            return
        }
        videoWidth = OldCameraManager.instance.previewWidth
        videoHeight = OldCameraManager.instance.previewHeight
        // 设置预览界面
        val surfaceTexture = previewSurfaceTexture
        if (surfaceTexture != null) {
            OldCameraManager.instance.startPreview(surfaceTexture, cameraPreviewCallback)
        }
    }

    private fun stopPreview() {
        OldCameraManager.instance.closeCamera()
    }

    //******************************** 录制 ********************************//

    /*** 摄像头预览帧数据回调 */
    private val cameraPreviewCallback = object : OldCameraManager.CameraPreviewCallback {
        override fun onPreviewFrame(data: ByteArray?, offset: Int, len: Int) {
            if (data == null) return
            val nd = ByteArray(len)
            System.arraycopy(data, offset, nd, 0, len)
            recordingTask?.writeVideoFrame(nd, videoWidth, videoHeight)
        }
    }
}

/**
 * 媒体编码器
 *
 * @author lkdont
 */
class MediaEncoder {

    companion object {
        private const val TAG = "MediaEncoder"
    }

    /*** 编码器参数 */
    class Config private constructor(
        val outputPath: String,
        // 视频参数
        val videoFormat: String?,
        val videoWidth: Int,
        val videoHeight: Int,
        val videoBitrate: Int,
        val videoFrameRate: Int,
        val videoIFrameInterval: Int
    ) {

        class Builder(val outputPath: String) {

            // 视频参数
            var videoFormat: String? = null
            fun videoFormat(videoFormat: String?) = apply { this.videoFormat = videoFormat }

            var videoWidth: Int = 0
            fun videoWidth(videoWidth: Int) = apply { this.videoWidth = videoWidth }

            var videoHeight: Int = 0
            fun videoHeight(videoHeight: Int) = apply { this.videoHeight = videoHeight }

            var videoBitrate: Int = 0
            fun videoBitrate(videoBitrate: Int) = apply { this.videoBitrate = videoBitrate }

            var videoFrameRate: Int = 0
            fun videoFrameRate(videoFrameRate: Int) = apply { this.videoFrameRate = videoFrameRate }

            var videoIFrameInterval: Int = 0
            fun videoIFrameInterval(videoIFrameInterval: Int) =
                apply { this.videoIFrameInterval = videoIFrameInterval }

            fun build() = Config(
                outputPath,
                videoFormat,
                videoWidth,
                videoHeight,
                videoBitrate,
                videoFrameRate,
                videoIFrameInterval
            )
        }

    }

    private lateinit var encoderConfig: Config
    private lateinit var outputStream: OutputStream

    fun start(config: Config) {
        encoderConfig = config
        // 初始化输出留
        outputStream = FileOutputStream(config.outputPath)
    }

    private var area: Rect? = null

    /*** 输入视频数据 */
    fun writeVideoData(presentationTimeUs: Long, data: ByteArray, length: Int) {
//        if (area == null) {
//            area = Rect(0, 0, encoderConfig.videoWidth, encoderConfig.videoHeight)
//        }
//        YuvImage(data, ImageFormat.NV21, encoderConfig.videoWidth, encoderConfig.videoHeight, null)
//            .compressToJpeg(area, 100, outputStream)
    }

    fun drainVideoEncoder(endOfStream: Boolean) {
        outputStream.flush()
    }

    fun stop() {
        try {
            outputStream.flush()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        try {
            outputStream.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

/*** 编码线程 */
class EncodeTask : Thread() {

    private var running = false

    override fun start() {
        running = true
        super.start()
    }

    fun stopRunning() {
        running = false
    }

    private class VideoFrame(
        val pts: Long,
        val data: ByteArray,
        val width: Int,
        val height: Int
    )

    private val videoFrameQueue = LinkedBlockingQueue<VideoFrame>()

    fun writeVideoFrame(data: ByteArray, width: Int, height: Int) {
        videoFrameQueue.put(VideoFrame(System.nanoTime() / 1000, data, width, height))
    }

    override fun run() {
        super.run()
        // 初始化编码器
        val config = MediaEncoder.Config.Builder("/sdcard/test-camera-video.mjpeg")
            .videoFormat("video/mjpeg")
            .videoBitrate(6000000)
            .videoFrameRate(30)
            .videoIFrameInterval(10)
            .videoWidth(1080)
            .videoHeight(1920)
            .build()
        val encoder = MediaEncoder()
        encoder.start(config)
        while (running) {
            val frame = videoFrameQueue.poll(50, TimeUnit.MILLISECONDS) ?: continue
            Log.d("TTTTT", "run: encoder.writeVideoData")
            encoder.writeVideoData(frame.pts, frame.data, frame.data.size)
            encoder.drainVideoEncoder(false)
        }
        encoder.drainVideoEncoder(true)
        encoder.stop()
    }

}